package logic.topology;

import gridsim.ParameterException;
import gridsim.net.SimpleLink;
import logic.topology.NetworkNode;


/**
 * Sietove spojenie medzi uzlami topologie.
 */
public class NetworkLink {

    private NetworkNode begin;
    private NetworkNode end;
    
    private String name;
    private double boudRate;
    private double propagationDelay;
    private int mtu;

    /**
     * Vytvorenie linky medzi uzlami a jej zaregistrovanie do GridTopology.
     * Ak linku nie je mozne vytvorit, vyhodi sa exception. Inac sa prida do
     * zoznamov oboch uzlov. Na orientacii linky nezalezi.
     * @param       beginNode       pociatocny uzol linky
     * @param       endNode         koncovy uzol linky
     */
    public NetworkLink(NetworkNode beginNode, NetworkNode endNode, String linkName) throws Exception {
        String can = null;

        if (beginNode == endNode)
            throw new Exception("Link can be created only between two different notes!");
        
        if (beginNode.hasLinkTo(endNode))
            throw new Exception("Link " + beginNode.getName() + " - " +
                    endNode.getName() + " already exists!");
        
        can = beginNode.canCreateNewLink();
        if (can != null) 
            throw new Exception(can);

        can = endNode.canCreateNewLink();
        if (can != null) 
            throw new Exception(can);
        
        can = beginNode.canCreateNewLink(endNode);
        if (can != null) 
            throw new Exception(can);
        
        can = endNode.canCreateNewLink(beginNode);
        if (can != null)
            throw new Exception(can);
        
        setName(linkName);

        begin = beginNode;
        end = endNode;
        boudRate = 1024;
        propagationDelay = 10;
        mtu = 1500;
        
        GridTopology.addLink(this);
        begin.insertLink(this);
        end.insertLink(this);
    }

    public NetworkNode getBegin() {
        return begin;
    }

    public NetworkNode getEnd() {
        return end;
    }

    /**
     * Ziskanie druheho konca linka. Ak dany uzol nie je na linke, vracia null
     * @param   node        pociatocny uzol linky
     * @return              koncovy uzol linky, ak zadany uzol je incidentny
     *                      uzol s danou linkou. Inak null.
     */
    public NetworkNode getAnotherEnd(NetworkNode node) {
        if (node == getBegin())
            return getEnd();
        else if (node == getEnd())
            return getBegin();
        else
            return null;
    }
    
    public String getName() {
        return name;
    }
    
    /**
     * Nastavenie mena linky.
     * @throws   Exception - linka s danym nazvom uz existuje alebo je retazec prazdny.
     */
    public void setName(String val) throws Exception {
        if (val.equals(name))
            return;                 //netreba nic nastavovat
        
        if (val.isEmpty())
            throw new Exception("Name must be defined!");
        
        if (GridTopology.existsLink(val))
            throw new Exception("Link with name " + val + " already exists!");
        
        name = new String(val);
    }
    
    /**
     * Odstranenie linky z GridTopology a zoznamov u incidentnych uzloch.
     */
    public void remove() {
        begin.removeLink(this);
        end.removeLink(this);
        GridTopology.removeLink(this);
    }

    /**
     * Vytvorenie linky z balika gridSim podla vlastnych parametrov
     * @return     ekvivalent z balika gridSim
     */
    public SimpleLink createSimpleLink() throws ParameterException {
        return new SimpleLink(getName(), getBoudRate(), getPropagationDelay(), getMtu());
    }
    
    public double getBoudRate() {
        return boudRate;
    }

    /**
     * Natavenie prenosovej rychlosti v bit/s. Musi byt > 0.
     */
    public void setBoudRate(double boudRate) {
        this.boudRate = boudRate;
    }

    public double getPropagationDelay() {
        return propagationDelay;
    }

    /**
     * Nastavenie oneskorenia prenosuv v milisekundach. Musi byt > 0.
     */
    public void setPropagationDelay(double propagationDelay) {
        this.propagationDelay = propagationDelay;
    }

    public int getMtu() {
        return mtu;
    }

    /**
     * Nastavenie maximalnej velkosti paketu v byte-och. Musi byt > 0.
     */
    public void setMtu(int mtu) {
        this.mtu = mtu;
    }
}
